package nl.fw.yapool.sql;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Cache for Named Parameter Statement.
 * @author Fred
 *
 */
public class NPSCache {

    /**
    * SingletonHolder is loaded on the first execution of Singleton.getInstance() 
    * or the first access to SingletonHolder.INSTANCE, not before.
    */
    private static class SingletonHolder { 
            public static final NPSCache INSTANCE = new NPSCache();
    }

    public static NPSCache getInstance() {
            return SingletonHolder.INSTANCE;
    }
    
	private final ConcurrentHashMap<String, Map<String, List<Integer>>> indexCache = new ConcurrentHashMap<String, Map<String, List<Integer>>>();
	private final ConcurrentHashMap<String, Map<String, List<Integer>>> indexArrayCache = new ConcurrentHashMap<String, Map<String, List<Integer>>>();
	private final ConcurrentHashMap<String, String> parsedQueryCache = new ConcurrentHashMap<String, String>();
	private final ConcurrentHashMap<String, String[]> parsedQueryArrayCache = new ConcurrentHashMap<String, String[]>();
	
	public NamedCache getCache(String namedQuery) {
		return new NamedCache(parsedQueryCache.get(namedQuery), indexCache.get(namedQuery));
	}

	public NamedArrayCache getCache(String namedQuery, int autoGeneratedKeys) {
		return new NamedArrayCache(parsedQueryArrayCache.get(namedQuery), indexArrayCache.get(namedQuery));
	}

	public void setCache(String namedQuery, String parsedQuery, Map<String, List<Integer>> m) {
		
		if (indexCache.putIfAbsent(namedQuery, m) == null) {
			parsedQueryCache.put(namedQuery, parsedQuery);
		}
	}

	public void setCache(String namedQuery, String parsedQueries[], Map<String, List<Integer>> m, int autoGeneratedKeys) {

		if (indexArrayCache.putIfAbsent(namedQuery, m) == null) {
			parsedQueryArrayCache.put(namedQuery, parsedQueries);
		}
	}
	
	public void clear() {
		
		indexCache.clear();
		parsedQueryCache.clear();
		indexArrayCache.clear();
		parsedQueryArrayCache.clear();
	}

	static final class NamedCache {
		
		private final Map<String, List<Integer>> indexMap;
		private final String parsedQuery;
		
		public NamedCache(String parsedQuery, Map<String, List<Integer>> indexMap) {
			this.parsedQuery = parsedQuery;
			this.indexMap = indexMap;
		}
		
		public boolean haveCache() {
			return (parsedQuery != null && indexMap != null);
		}
		
		public Map<String, List<Integer>> getIndexMap() { return indexMap; }
		public String getParsedQuery() { return parsedQuery; }
	}
	
	static final class NamedArrayCache {
		
		private final Map<String, List<Integer>> indexMap;
		private final String[] parsedQuery;
		
		public NamedArrayCache(String[] parsedQuery, Map<String, List<Integer>> indexMap) {
			this.parsedQuery = parsedQuery;
			this.indexMap = indexMap;
		}
		
		public boolean haveCache() {
			return (parsedQuery != null && indexMap != null);
		}
		
		public Map<String, List<Integer>> getIndexMap() { return indexMap; }
		public String[] getParsedQuery() { return parsedQuery; }
	}

}
